package com.woniu.his.mms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.woniu.his.dms.client.CaseHistoryClient;
import com.woniu.his.dms.client.result.CaseHistoryResult;
import com.woniu.his.exception.HisException;
import com.woniu.his.mms.common.MmsResultCode;
import com.woniu.his.mms.common.enums.MmsStatusEnums;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniu.his.mms.common.MmsStatusEnum.MmsStatusCode;
import com.woniu.his.mms.infra.model.*;
import com.woniu.his.mms.infra.mapper.DrugMapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.his.mms.service.*;
import com.woniu.his.mms.service.dto.*;
import com.woniu.his.mms.service.param.*;
import com.woniu.his.pms.client.PmsPatientClient;
import com.woniu.his.pms.client.result.PatientResult;
import com.woniu.his.pms.client.result.StartDiagnosePatientResult;
import com.woniu.his.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 药品 服务实现类
 * </p>
 *
 * @author ZJH
 * @since 2022-11-28
 */
@Service
@Slf4j
public class DrugServiceImpl extends ServiceImpl<DrugMapper, Drug> implements DrugService {

    @Resource
    private Snowflake snowflake;

    @Resource
    private DrugTypeService drugTypeService;

    @Resource
    private DosageService dosageService;

    @Resource
    private HerbalPrescriptionRecordService heService;

    @Resource
    private MedicinePrescriptionRecordService medicineService;

    @Resource
    private HerbalItemRecordService herService;

    @Resource
    private MedicineItemRecordService itemRecordService;


    @Resource
    private DrugRefundItemRecordService recipeRefundItemRecordService;


    @Resource
    private PmsPatientClient pmsPatientClient;

    @Resource
    private DrugService drugService;

    @Resource
    private CaseHistoryClient caseHistoryClient;

    @Override
    public void addDrug(AddDrugServicePram servicePram) {

        //判断剂型是否存在
        Dosage byId1 = dosageService.getById(servicePram.getDosageId());
        if (byId1 == null) throw new HisException(MmsResultCode.DRUG_DOSAGE_NOT_EXIST);

        //判断药品类型是否存在
        DrugType byId = drugTypeService.getById(servicePram.getTypeId());
        if (byId == null) throw new HisException(MmsResultCode.DRUG_TYPE_NOT_EXIST);

        //药名不能重
        QueryWrapper<Drug> wrapper = new QueryWrapper<>();
        wrapper.eq("name_drug", servicePram.getNameDrug());
        Drug one = getOne(wrapper);
        if (one != null) throw new HisException(MmsResultCode.DRUG_IS_EXIST);

        Drug drug = BeanUtil.copyProperties(servicePram, Drug.class);
        drug.setCodeDrug("drug" + snowflake.nextId());
        drug.setCreateDate(new Date());
        drug.setStatusDrug(MmsStatusEnums.ON.getCode());

        save(drug);

    }

    @Override
    public void addDosage(AddDosageServiceParam param1) {

        QueryWrapper<Dosage> wrapper = new QueryWrapper<>();
        wrapper.eq("name_dosgae", param1.getNameDosgae());
        Dosage one = dosageService.getOne(wrapper);
        if (one != null) throw new HisException(MmsResultCode.DRUG_DOSAGE_IS_EXIST);
        Dosage dosage = BeanUtil.copyProperties(param1, Dosage.class);
        dosage.setStatusDosage(MmsStatusEnums.ON.getCode());
        dosageService.save(dosage);

    }

    @Override
    public List<DosageDto> queryAllDosage() {

        QueryWrapper<Dosage> wrapper = new QueryWrapper<>();
        wrapper.eq("status_dosage", MmsStatusEnums.ON.getCode());
        List<Dosage> list = dosageService.list(wrapper);
        return BeanUtil.copyToList(list, DosageDto.class);
    }

    @Override
    public void deleteDrugByIds(List<Long> ids) {

        removeByIds(ids);
    }

    @Override
    public PageDrugDto findDrug(FindDrugServiceParam serviceParam) {

        Long current = serviceParam.getCurrent() == null ? 1 : serviceParam.getCurrent();
        Long size = serviceParam.getSize() == null ? 1 : serviceParam.getSize();

        QueryWrapper<Drug> wrapper = new QueryWrapper<>();
        //条件0：选择有效的
        wrapper.eq("status_drug", MmsStatusEnums.ON.getCode());

        //条件1：关键字（科室名，科室编码）是否存在
        if (serviceParam.getKeyword() != null && serviceParam.getKeyword().trim().length() > 0) {
            wrapper.and(w -> {
                w.like("code_drug", serviceParam.getKeyword()).or().like("name_drug", serviceParam.getKeyword())
                        .or().like("manufacturer", serviceParam.getKeyword()).or().like("mnemonic_code", serviceParam.getKeyword())
                        .or().like("generic_name", serviceParam.getKeyword());
            });
        }
        //最终查询数据
        IPage<Drug> page = page(new Page<>(current, size), wrapper);
        if (page.getRecords().size() <= 0) return null;
        PageDrugDto pageDrugDto = new PageDrugDto();
        List<DrugDto> list = BeanUtil.copyToList(page.getRecords(), DrugDto.class);
        pageDrugDto.setDrugResults(list);
        pageDrugDto.setCurrent(page.getCurrent());
        pageDrugDto.setSize(page.getSize());
        pageDrugDto.setTotal(page.getTotal());
        return pageDrugDto;
    }

    @Override
    public void updateDrug(UpdateDrugServiceParam serviceParam) {

        //药品是否存在
        Drug one = getById(serviceParam.getId());
        if (one == null) throw new HisException(MmsResultCode.DRUG_NOT_EXIST);
        //判断类型是否存在
        DrugType t = drugTypeService.getById(serviceParam.getTypeId());
        if (t == null) throw new HisException(MmsResultCode.DRUG_TYPE_NOT_EXIST);
        //判断剂型是否存在
        Dosage d = dosageService.getById(serviceParam.getDosageId());
        if (d == null) throw new HisException(MmsResultCode.DRUG_DOSAGE_NOT_EXIST);

        one = BeanUtil.copyProperties(serviceParam, Drug.class);
        one.setCreateDate(new Date());
        updateById(one);

    }

    /**
     * 刷新拿药患者
     *
     * @param param
     * @return
     */
    @Override
    public PatientDto listPatient(PatienServiceParam param) {

        //根据type(4草药 HELBAL 5成药 MEDICINE)判断处方类型
        if (param.getType().equals("HELBAL")) {
            //这是草药处方患者信息
            return listWhenHerbal(param.getQuerydate(), param.getMedicalRecordNo());

        } else if (param.getType().equals("MEDICINE")) {
            //这是成药处方患者信息
            return listWhenMedicine(param.getQuerydate(), param.getMedicalRecordNo());
        }
        //其他类型直接返回null
        return null;
    }

    /**
     * 发药
     *
     * @param param
     * @return
     */
    @Override
    public boolean releaseDrug(ReleaseDrugServiceParam param) {
        if (param.getType().equals("HELBAL")) {
            //这是草药处方 将状态改查已完成
            List<HerbalItemRecord> prescription_id = herService.list(new QueryWrapper<HerbalItemRecord>().eq("prescription_id", param.getPrescriptionId()));
            HerbalPrescriptionRecord prescription_id1 = heService.getById(param.getPrescriptionId());
            if (prescription_id1 == null || prescription_id.size() <= 0) {
                throw new HisException(MmsResultCode.DRUG_NOT_EXIST);
            }
            for (HerbalItemRecord herbalItemRecord : prescription_id) {
                if (herbalItemRecord.getStatusHir().equals(MmsStatusCode.ITEM_STATUS_HOLD.getCode()))
                    throw new HisException(MmsResultCode.DEMO_CODE);
                herbalItemRecord.setStatusHir(MmsStatusCode.ITEM_STATUS_HOLD.getCode());
                Drug byId1 = drugService.getById(herbalItemRecord.getDrugId());
                byId1.setStock(byId1.getStock() - herbalItemRecord.getTotalNum());
                drugService.updateById(byId1);
            }
            prescription_id1.setHerbalPrescriptionStatus(MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_FINISH.getCode());
            herService.updateBatchById(prescription_id);
            heService.updateById(prescription_id1);


        } else if (param.getType().equals("MEDICINE")) {
            //这是成药处方
            MedicinePrescriptionRecord prescription_id = medicineService.getById(param.getPrescriptionId());
            List<MedicineItemRecord> prescription_id1 = itemRecordService.list(new QueryWrapper<MedicineItemRecord>().eq("prescription_id", param.getPrescriptionId()));
            if (prescription_id1.size() <= 0 || prescription_id == null) {
                throw new HisException(MmsResultCode.DRUG_NOT_EXIST);
            }
            prescription_id.setMedicinePrescriptionStatus(MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_FINISH.getCode());

            for (MedicineItemRecord medicineItemRecord : prescription_id1) {
                medicineItemRecord.setMedicineItemStatus(MmsStatusCode.ITEM_STATUS_HOLD.getCode());
                Drug byId1 = drugService.getById(medicineItemRecord.getDrugId());
                byId1.setStock(byId1.getStock() - medicineItemRecord.getNum());
                drugService.updateById(byId1);
            }
            medicineService.updateById(prescription_id);
            itemRecordService.updateBatchById(prescription_id1);
        }
        return true;
    }

    /**
     * 退药
     *
     * @param param
     * @return
     */
    @Override
    public boolean refundDrug(RefundDrugServiceParam param) {
        List<DmsRefundDrugServiceParam> refundItemList = param.getRefundItemList();
        for (DmsRefundDrugServiceParam dmsRefundDrugServiceParam : refundItemList) {
            if (dmsRefundDrugServiceParam.getType().equals("HELBAL")) {
                //这是草药处理退药
                HerbalItemRecord prescription_id = herService.getOne(new QueryWrapper<HerbalItemRecord>().
                        eq("id", dmsRefundDrugServiceParam.getRefundPrescriptionItemId()));
                if (prescription_id == null) return false;
                //如果是拿药的 或者是退药 或者是已经
                if (!prescription_id.getStatusHir().equals(MmsStatusCode.ITEM_STATUS_HOLD.getCode())
                        || prescription_id.getTotalNum() < dmsRefundDrugServiceParam.getRefundNum()) {
                    return false;
                }
                prescription_id.setStatusHir(MmsStatusCode.ITEM_STATUS_RETURN_DRUGS.getCode());
                prescription_id.setUsageNum(prescription_id.getTotalNum() - dmsRefundDrugServiceParam.getRefundNum());
                herService.updateById(prescription_id);
                HerbalPrescriptionRecord byId = heService.getById(prescription_id.getPrescriptionId());
                DrugRefundItemRecord drugRefundItemRecord = new DrugRefundItemRecord();
                drugRefundItemRecord.setStatusDrugRefund("REFUND");
                drugRefundItemRecord.setType("HELBAL");
                drugRefundItemRecord.setCaseHistoryId(byId.getCaseHistoryId());
                drugRefundItemRecord.setDrugId(prescription_id.getDrugId());
                drugRefundItemRecord.setRefundNumUnit(prescription_id.getUsageNumUnit());
                drugRefundItemRecord.setRefundNum(dmsRefundDrugServiceParam.getRefundNum());
                drugRefundItemRecord.setRefundTime(new Date());
                drugRefundItemRecord.setExcutorId(param.getExcutorId());
                drugRefundItemRecord.setRefundItemRecordId(prescription_id.getId());
                recipeRefundItemRecordService.save(drugRefundItemRecord);
                Drug byId1 = drugService.getById(prescription_id.getDrugId());
                byId1.setStock(byId1.getStock() + dmsRefundDrugServiceParam.getRefundNum());
                drugService.updateById(byId1);
            } else if (dmsRefundDrugServiceParam.getType().equals("MEDICINE")) {
                //这是成药处方处理退药
                MedicineItemRecord prescription_id = itemRecordService.getOne(new QueryWrapper<MedicineItemRecord>().
                        eq("id", dmsRefundDrugServiceParam.getRefundPrescriptionItemId()));
                if (prescription_id == null) return false;

                //如果是拿药的 或者是退药 或者是已经
                if (!prescription_id.getMedicineItemStatus().equals(MmsStatusCode.ITEM_STATUS_HOLD.getCode())
                        || prescription_id.getNum() <dmsRefundDrugServiceParam.getRefundNum()) {
                    return false;
                }
                prescription_id.setMedicineItemStatus(MmsStatusCode.ITEM_STATUS_RETURN_DRUGS.getCode());
                prescription_id.setRefundNum(dmsRefundDrugServiceParam.getRefundNum());
                prescription_id.setUsageNum(prescription_id.getNum()-dmsRefundDrugServiceParam.getRefundNum());
                itemRecordService.updateById(prescription_id);
                MedicinePrescriptionRecord byId = medicineService.getById(prescription_id.getPrescriptionId());
                DrugRefundItemRecord drugRefundItemRecord = new DrugRefundItemRecord();
                drugRefundItemRecord.setStatusDrugRefund("REFUND");
                drugRefundItemRecord.setType("MEDICINE");
                drugRefundItemRecord.setCaseHistoryId(byId.getCaseHistoryId());
                drugRefundItemRecord.setDrugId(prescription_id.getDrugId());
                drugRefundItemRecord.setRefundNumUnit(prescription_id.getUsageNumUnit());
                drugRefundItemRecord.setRefundNum(dmsRefundDrugServiceParam.getRefundNum());
                drugRefundItemRecord.setRefundTime(new Date());
                drugRefundItemRecord.setExcutorId(param.getExcutorId());
                drugRefundItemRecord.setRefundItemRecordId(prescription_id.getId());
                recipeRefundItemRecordService.save(drugRefundItemRecord);
                Drug byId1 = drugService.getById(prescription_id.getDrugId());
                byId1.setStock(byId1.getStock() + dmsRefundDrugServiceParam.getRefundNum());
                drugService.updateById(byId1);
            }
        }
        return true;
    }

    /**
     * 查询草药患者
     *
     * @param querydate
     * @param medicalRecordNo
     * @return
     */
    private PatientDto listWhenMedicine(Date querydate, String medicalRecordNo) {

        log.info("正在查询成药处方:{}", medicalRecordNo);
        //这是没有拿药的处方
        List<PmsDrugStorePatientDto> undoPatientList = new ArrayList<>();
        //这是已经拿药的处方
        List<PmsDrugStorePatientDto> donePatientList = new ArrayList<>();
        //在处方表中根据时间查询
        //在处方表中根据时间查询
        List<Date> dateList = createDate(querydate);

        log.info("开始时间:{}",dateList.get(0));
        log.info("结束时间:{}",dateList.get(1));

        QueryWrapper<MedicinePrescriptionRecord> wrapper = new QueryWrapper<>();
        wrapper.ne("medicine_prescription_status", MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_DELETE.getCode());
        wrapper.ge("create_time", dateList.get(0));
        wrapper.le("create_time", dateList.get(1));
        List<MedicinePrescriptionRecord> list = medicineService.list(wrapper);
        //病例id和处方id
        log.info("符合时间段的全部成药处方:{}",list);
        Map<Long, List<Long>> undoPatientToRecord = new HashMap<>();
        Map<Long, List<Long>> donePatientToRecord = new HashMap<>();
        for (MedicinePrescriptionRecord record : list) {
            //判断状态 这是没有拿到药的 并且用病例id去重
            if (record.getMedicinePrescriptionStatus().equals(MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_PAID.getCode())) {
                if (undoPatientToRecord.get(record.getCaseHistoryId()) == null) {
                    List<Long> longList = new ArrayList<>();
                    longList.add(record.getId());
                    undoPatientToRecord.put(record.getCaseHistoryId(), longList);
                } else {
                    List<Long> longList = undoPatientToRecord.get(record.getCaseHistoryId());
                    longList.add(record.getId());
                    undoPatientToRecord.put(record.getCaseHistoryId(), longList);
                }
                //这是已经拿到药的
            } else if (record.getMedicinePrescriptionStatus().equals("FINISH")) {
                if (donePatientToRecord.get(record.getCaseHistoryId()) == null) {
                    List<Long> longList = new ArrayList<>();
                    longList.add(record.getId());
                    donePatientToRecord.put(record.getCaseHistoryId(), longList);
                } else {
                    List<Long> longList = donePatientToRecord.get(record.getCaseHistoryId());
                    longList.add(record.getId());
                    donePatientToRecord.put(record.getCaseHistoryId(), longList);
                }
            }
        }
        //然后再根据病例id 去封装病人的信息
        log.info("没拿药病人id+处方id:{}",undoPatientToRecord);
        log.info("已经拿药病人id+处方id:{}",donePatientToRecord);
        //然后再根据病例id 去封装病人的信息
        for (Map.Entry<Long, List<Long>> entry : undoPatientToRecord.entrySet()) {

            CaseHistoryResult data = caseHistoryClient.queryById(entry.getKey()).getData();
            if (data != null) {
//                List<PatientResult> patient = pmsPatientClient.queryPatient(ids).getData();
//                if (patient.get(0) == null) continue;
                PmsDrugStorePatientDto dto = new PmsDrugStorePatientDto();
                dto.setPrescriptionIdList(donePatientToRecord.get(entry.getValue()));
                dto.setPatientName(data.getPatientName());
                dto.setPatientId(data.getPatientId());
                dto.setMedicalRecordNo(data.getAgeStr());
                undoPatientList.add(dto);
            }
        }
        for (Map.Entry<Long, List<Long>> entry : donePatientToRecord.entrySet()) {
            CaseHistoryResult data = caseHistoryClient.queryById(entry.getKey()).getData();
            if (data != null) {
//                List<PatientResult> patient = pmsPatientClient.queryPatient(ids).getData();
//                if (patient.get(0) == null) continue;
                PmsDrugStorePatientDto dto = new PmsDrugStorePatientDto();
                dto.setPrescriptionIdList(donePatientToRecord.get(entry.getValue()));
                dto.setPatientName(data.getPatientName());
                dto.setPatientId(data.getPatientId());
                dto.setMedicalRecordNo(data.getAgeStr());
                donePatientList.add(dto);
            }
        }

        PatientDto patientDto = new PatientDto();
        patientDto.setDonePatientList(donePatientList);
        patientDto.setUndoPatientList(undoPatientList);
        return patientDto;
    }

    /**
     * 获取给定一个时间的 时间段
     *
     * @param querydate
     * @return
     */
    public List<Date> createDate(Date querydate) {
        List<Date> dateList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(querydate);
        // 设置时分秒毫秒为0:0:0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        dateList.add(calendar.getTime());

        // 设置时分秒毫秒为23:59:59:999
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        dateList.add(calendar.getTime());
        return dateList;
    }

    ;

    /**
     * 查询成药患者
     *
     * @param querydate
     * @param medicalRecordNo
     * @return
     */
    private PatientDto listWhenHerbal(Date querydate, String medicalRecordNo) {
        log.info("正在查询草药处方:{}", medicalRecordNo);
        //这是没有拿药的处方
        List<PmsDrugStorePatientDto> undoPatientList = new ArrayList<>();
        //这是已经拿药的处方
        List<PmsDrugStorePatientDto> donePatientList = new ArrayList<>();
        //在处方表中根据时间查询
        //在处方表中根据时间查询
        List<Date> dateList = createDate(querydate);
        log.info("开始时间:{}",dateList.get(0));
        log.info("结束时间:{}",dateList.get(1));
        QueryWrapper<HerbalPrescriptionRecord> wrapper = new QueryWrapper<>();
        wrapper.ne("herbal_prescription_status", MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_DELETE.getCode());
        wrapper.ge("create_time", dateList.get(0));
        wrapper.le("create_time", dateList.get(1));

        List<HerbalPrescriptionRecord> list = heService.list(wrapper);
        log.info("符合时间段的全部草药处方信息:{}",list);
        //病例id和处方id
        Map<Long, List<Long>> undoPatientToRecord = new HashMap<>();
        Map<Long, List<Long>> donePatientToRecord = new HashMap<>();
        for (HerbalPrescriptionRecord record : list) {
            //判断状态 这是没有拿到药的 并且用病例id去重
            if (record.getHerbalPrescriptionStatus().equals(MmsStatusCode.HERBAL_PRESCRIPTION_STATUS_PAID.getCode())) {
                if (undoPatientToRecord.get(record.getCaseHistoryId()) == null) {
                    List<Long> longList = new ArrayList<>();
                    longList.add(record.getId());
                    undoPatientToRecord.put(record.getCaseHistoryId(), longList);
                } else {
                    List<Long> longList = undoPatientToRecord.get(record.getCaseHistoryId());
                    longList.add(record.getId());
                    undoPatientToRecord.put(record.getCaseHistoryId(), longList);
                }
                //这是已经拿到药的
            } else if (record.getHerbalPrescriptionStatus().equals("FINISH")) {
                if (donePatientToRecord.get(record.getCaseHistoryId()) == null) {
                    List<Long> longList = new ArrayList<>();
                    longList.add(record.getId());
                    donePatientToRecord.put(record.getCaseHistoryId(), longList);
                } else {
                    List<Long> longList = donePatientToRecord.get(record.getCaseHistoryId());
                    longList.add(record.getId());
                    donePatientToRecord.put(record.getCaseHistoryId(), longList);
                }
            }
        }
        //然后再根据病例id 去封装病人的信息
        log.info("没拿药病人id+处方id:{}",undoPatientToRecord);
        log.info("已经拿药病人id+处方id:{}",donePatientToRecord);
        //然后再根据病例id 去封装病人的信息
        for (Map.Entry<Long, List<Long>> entry : undoPatientToRecord.entrySet()) {

            CaseHistoryResult data = caseHistoryClient.queryById(entry.getKey()).getData();
            if (data != null) {
//                List<PatientResult> patient = pmsPatientClient.queryPatient(ids).getData();
//                if (patient.get(0) == null) continue;
                PmsDrugStorePatientDto dto = new PmsDrugStorePatientDto();
                dto.setPrescriptionIdList(donePatientToRecord.get(entry.getValue()));
                dto.setPatientName(data.getPatientName());
                dto.setPatientId(data.getPatientId());
                dto.setMedicalRecordNo(data.getAgeStr());
                undoPatientList.add(dto);
            }
        }
        for (Map.Entry<Long, List<Long>> entry : donePatientToRecord.entrySet()) {
            CaseHistoryResult data = caseHistoryClient.queryById(entry.getKey()).getData();
            if (data != null) {
//                List<PatientResult> patient = pmsPatientClient.queryPatient(ids).getData();
//                if (patient.get(0) == null) continue;
                PmsDrugStorePatientDto dto = new PmsDrugStorePatientDto();
                dto.setPrescriptionIdList(donePatientToRecord.get(entry.getValue()));
                dto.setPatientName(data.getPatientName());
                dto.setPatientId(data.getPatientId());
                dto.setMedicalRecordNo(data.getAgeStr());
                donePatientList.add(dto);
            }
        }
        PatientDto patientDto = new PatientDto();
        patientDto.setDonePatientList(donePatientList);
        patientDto.setUndoPatientList(undoPatientList);

        return patientDto;
    }

    @Override
    public List<DrugDto> queryAllDrug() {
        List<Drug> drugs = list(new QueryWrapper<Drug>().eq("status_drug", MmsStatusCode.DRUG_STATUS_ON.getCode()));
        return BeanUtil.copyToList(drugs, DrugDto.class);
    }
}
